import json
from datetime import datetime
from http.server import BaseHTTPRequestHandler

from request import post_req
from recommend import recommend, cancel, show_my_recommendation, how_much_recommendation, history, subscribe, article_recommend


def get_bot_handler(config):
    """
    通过 config 配置一个基础的飞书机器人，里面大部分的方法的命名均不能修改
    
    :param config: 配置文件
    :return:
    """
    
    class RequestHandler(BaseHTTPRequestHandler):
        
        def do_GET(self):
            requestline = str(self.raw_requestline, 'iso-8859-1').split(' ')
            # 响应请求
            if '/recommend' in requestline[1]:
                index = requestline[1].rindex('/')
                print(requestline[1][index + 1:])
                try:
                    times = article_recommend(requestline[1][index + 1:])
                    if times:
                        message = "推荐成功，已推荐{}次".format(times)
                    else:
                        message = "推荐失败"
                except Exception as e:
                    message = e
                self.responseMsg(f'<html><b>{message}</b></html>')
        
        def do_POST(self):  # 看起来这个名字不能改
            # 解析请求 body
            req_body = self.rfile.read(int(self.headers['content-length']))
            obj = json.loads(req_body.decode("utf-8"))
            print(req_body)
            
            # 校验 verification token 是否匹配，token 不匹配说明该回调并非来自开发平台
            token = obj.get("token", "")
            if token != config.APP_VERIFICATION_TOKEN:
                print("verification token not match, token =", token)
                self.response("")
                return
            
            # 根据 type 处理不同类型事件
            type = obj.get("type", "")
            if "url_verification" == type:  # 验证请求 URL 是否有效
                self.handle_request_url_verify(obj)
            elif "event_callback" == type:  # 事件回调
                # 获取事件内容和类型，并进行相应处理，此处只关注给机器人推送的消息事件
                event = obj.get("event")
                if event.get("type", "") == "message":
                    self.handle_message(event)
                    return
            return
        
        def handle_request_url_verify(self, post_obj):
            # 原样返回 challenge 字段内容
            challenge = post_obj.get("challenge", "")
            rsp = {'challenge': challenge}
            self.response(json.dumps(rsp))
            return
        
        def handle_message(self, event):
            # 此处只处理 text 类型消息，其他类型消息忽略
            msg_type = event.get("msg_type", "")
            user_id = event.get("open_id")
            if msg_type != "text":
                print("unknown msg_type =", msg_type)
                self.response("")
                return
            
            # 调用发消息 API 之前，先要获取 API 调用凭证：tenant_access_token
            access_token = config.tenant_access_token()
            if access_token == "":
                self.response("")
                return
            else:
                print("access_token", access_token)

            msg = event.get("text_without_at_bot").strip()
            if msg == 'help':
                self.send_help_card(access_token, user_id)
            elif msg.startswith("history-") or msg.startswith("h-"):
                try:
                    if msg.startswith("history-"):
                        msg = msg[8:].strip()
                        resp = history(datetime.strptime(msg, '%Y.%m.%d'))
                    else:
                        msg = msg[2:].strip()
                        resp = history(datetime.strptime(msg, '%Y.%m.%d'))
                    if resp is None:
                        resp = f'未查询到{msg}的论文推荐'
                        self.send_message(access_token, user_id, resp)
                    else:
                        self.send_post(access_token, user_id, resp)
                except:
                    resp = '请按规定格式输入日期，如：history-2021.9.7'
                    self.send_message(access_token, user_id, resp)
            else:
                resp = self.process(msg, user_id)
                # 机器人 echo 收到的消息
                self.send_message(access_token, user_id, resp)
            self.response("")
            return
        
        def response(self, body):
            self.send_response(200)
            self.send_header('Content-Type', 'application/json')
            self.end_headers()
            self.wfile.write(body.encode())
        
        def responseMsg(self, msg):
            self.send_response(200)
            self.send_header("Content-type", "text/html;charset=gbk")
            self.end_headers()
            self.wfile.write(msg.encode('gbk'))
        
        @staticmethod
        def send_message(token, open_id, text):
            url = "https://open.feishu.cn/open-apis/message/v4/send/"
            
            headers = {
                "Content-Type": "application/json",
                "Authorization": "Bearer " + token
            }
            req_body = {
                "open_id": open_id,
                "msg_type": "text",
                "content": {
                    "text": text
                }
            }
            
            rsp_dict = post_req(url, headers, req_body)
            
            code = rsp_dict.get("code", -1)
            if code != 0:
                print("send message error, code = ", code, ", msg =", rsp_dict.get("msg", ""))

        @staticmethod
        def send_post(token, open_id, data):
            url = "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=open_id"
            
            headers = {
                "Content-Type": "application/json",
                "Authorization": "Bearer " + token
            }
            req_body = {
                "receive_id": open_id,
                "msg_type": "post",
                "content": json.dumps({
                    "zh_cn": {
                        "content": [
                            [
                                {
                                    "tag": "a",
                                    "href": data['docNo'],
                                    "text": data['docTitle']
                                }
                            ]
                        ]
                    }
                }),
            }
            
            rsp_dict = post_req(url, headers, req_body)
            
            code = rsp_dict.get("code", -1)
            if code != 0:
                print("send message error, code = ", code, ", msg =", rsp_dict.get("msg", ""))        

        @staticmethod
        def send_help_card(token, open_id):
            url = "https://open.feishu.cn/open-apis/message/v4/send/"
            
            headers = {
                "Content-Type": "application/json",
                "Authorization": "Bearer " + token
            }
            req_body = {
                "open_id": open_id,
                "msg_type": "interactive",
                "card": {
                    "config": {
                        "wide_screen_mode": True
                    },
                    "header": {
                        "title": {
                            "tag": "plain_text",
                            "content": "关键词推荐-帮助"
                        },
                        "template": "blue"
                    },
                    "elements": [
                        {
                            "tag": "markdown",
                            "content":  "**操作命令**\n"\
                                        "**recommend-[W]** or **r-[W]**\n\t推荐关键词[W]\n\t如：recommend-classification\n\t(关键词不区分大小写)\n"\
                                        "**cancel-[W]** or **c-[W]**\n\t取消推荐关键词[W]\n"\
                                        "**recommendation num-[W]** or **rnum-[W]**\n\t查询关键词[W]推荐人数\n"\
                                        "**show my recommendation** or **show**\n\t查询已推荐的关键词\n"\
                                        "**history-[D]** or **h-[D]**\n\t查询历史推荐论文\n\t如：history-2021.9.7\n"\
                                        "**subscribe**\n\t机器人单独发送每日论文\n"\
                                        "**unsubscribe**\n\t取消单独发送\n\n"    
                        },
                        {
                            "tag": "note",
                            "elements": [
                                {
                                    "tag": "lark_md",
                                    "content":  "**说明**\n"
                                                "论文推荐机器人会根据推荐词在当天arXiv更新的论文中进行筛选。"\
                                                "只要在论文的作者、标题或摘要中出现过推荐词就会增加论文相应的得分，论文得分越高，越有可能被推荐。"\
                                                "打分规则是**推荐人数越多的推荐词权重越高**；**已经推荐过的推荐词权重会下降**；**权重会定期重置**\n"\
                                }
                            ]
                        }, 
                        {
                            "tag": "hr"
                        },
                        {  
                            "tag":"img",
                            "img_key":"img_v2_29c043eb-d9c1-4e6a-a1f5-272aefeb3d1g",
                            "mode": "fit_horizontal",
                            "alt":{  
                                "tag":"plain_text",
                                "content":"看paper"
                            }
                        }
                    ]
                }
            }
            
            rsp_dict = post_req(url, headers, req_body)
            
            code = rsp_dict.get("code", -1)
            if code != 0:
                print("send message error, code = ", code, ", msg =", rsp_dict.get("msg", ""))
        
        @staticmethod
        def process(msg: str, openId: str) -> str:
            if msg.startswith("recommend-"):
                resp = recommend(msg[10:].strip(), openId)
            elif msg.startswith("r-"):
                resp = recommend(msg[2:].strip(), openId)
            elif msg.startswith("cancel-"):
                resp = cancel(msg[7:].strip(), openId) 
            elif msg.startswith("c-"):
                resp = cancel(msg[2:].strip(), openId) 
            # elif "recommend author-" in msg:
            #     resp = recommend_author(msg.replace("recommend author-", "").strip(), openId)
            # elif "cancel author-" in msg:
            #     resp = cancel_author(msg.replace("cancel author-", "").strip(), openId)
            elif msg.startswith("recommendation num-"):
                resp = how_much_recommendation(msg[19:].strip())
            elif msg.startswith("rnum-"):
                resp = how_much_recommendation(msg[5:].strip())
            elif msg == "subscribe":
                subscribe(openId) 
                resp = "关注成功"
            elif msg == "unsubscribe":
                subscribe(openId, False) 
                resp = "取关成功"
            elif msg == "show my recommendation" or msg == "show":
                resp = show_my_recommendation(openId)
            else:
                resp = '未指定的命令，请输入 help 查看操作'
            return resp
    
    return RequestHandler
